home *** CD-ROM | disk | FTP | other *** search
/ SGI Hot Mix 17 / Hot Mix 17.iso / HM17_SGI / research / examples / demo / demosrc / d_venn.pro < prev    next >
Text File  |  1997-07-08  |  66KB  |  1,992 lines

  1. ;$Id: d_venn.pro,v 1.14 1997/04/23 15:02:01 ghayman Exp $
  2. ;
  3. ;  Copyright (c) 1997, Research Systems, Inc. All rights reserved.
  4. ;       Unauthorized reproduction prohibited.
  5. ;
  6. ;+
  7. ;  FILE:
  8. ;       d_venn.pro
  9. ;
  10. ;  CALLING SEQUENCE: d_venn
  11. ;
  12. ;  PURPOSE:
  13. ;       Visualize the result of set theory operations through
  14. ;       Venn diagrams.
  15. ;
  16. ;  MAJOR TOPICS: Visualization
  17. ;
  18. ;  CATEGORY:
  19. ;       IDL 5.0
  20. ;
  21. ;  INTERNAL FUNCTIONS and PROCEDURES:
  22. ;       pro PlotCircle           -  Plot a circle
  23. ;       pro PlaceVennLegend      -  Place the legend
  24. ;       pro DrawVennDiagram      -  Draw the Venn diagram
  25. ;       fun SetsIntersect        -  Obtain the intersection of two sets
  26. ;       fun SetsSubtract         -  Obtain the subtraction of two sets
  27. ;       fun SetsUnion            -  Obtain the union of two sets
  28. ;       pro DataViewerHandler    -  Event handler for viewing data
  29. ;       fun DataViewer           -  View the data set
  30. ;       fun TypeOf               -  Find the data type of a variable
  31. ;       fun ValidSetData         -  Determine the validity of a set
  32. ;       pro LoadCalcBitmap       -  Load the bitmaps buttons
  33. ;       pro CreateSet            -  Create a new set
  34. ;       fun DoSetOp              -  Do the set operation
  35. ;       fun ModifyCalcText       -  Modify the calculator text
  36. ;       pro SetCalcButtonHandler -  Event handler for calculator button
  37. ;       pro SetCalcHandleEvents  -  Event handler for calculator
  38. ;                                   other than button
  39. ;       pro CleanupVenn          -  Cleanup
  40. ;       pro VennHandleEvent      -  Main event handler
  41. ;       pro D_Venn                 -  Main procedure
  42. ;
  43. ;  EXTERNAL FUNCTIONS, PROCEDURES, and FILES:
  44. ;       sets__define.pro         -  Class definition file for the 'sets' class
  45. ;
  46. ;  REFERENCE: IDL Reference Guide, IDL User's Guide
  47. ;
  48. ;  NAMED STRUCTURES:
  49. ;       NONE
  50. ;
  51. ;  COMMON BLOCS:
  52. ;       NONE
  53. ;
  54. ;  MODIFICATION HISTORY:
  55. ;       3/97,   GH, SK   - Written.
  56. ;-
  57. ;----------------------------------------------------------------------------
  58. ;
  59. ;  PURPOSE: Plot circles for Venn diagrams.
  60. ;
  61. pro PlotCircle, $
  62.     radius, $            ; IN: circle radius in pixels
  63.     position, $          ; IN: x and y position of the circle
  64.     NOERASE = noErase, $ ; IN: (opt) Erase previous plot (0=no,1=yes)
  65.     COLOR = color        ; IN: (opt) Color index to fill the circle
  66.  
  67.     if (not (KEYWORD_SET (noErase))) then $
  68.         noErase = 0
  69.  
  70.     position[0] = 0.99999 * position[0]
  71.     position[1] = 0.99999 * position[1]
  72.     position[2] = 1.00009 * position[2]
  73.     position[3] = 1.00009 * position[3]
  74.     ro = FLTARR(180) + radius
  75.     to = FINDGEN(180) * 4.0 * !PI / 180.0
  76.  
  77.     PLOT, ro, to, /POLAR, /DEVICE, POSITION=position, $
  78.         XSTYLE=5, YSTYLE=5, NOERASE=noErase, COLOR=color, $
  79.         THICK=1.2
  80.  
  81. end
  82.  
  83. ;----------------------------------------------------------------------------
  84. ;
  85. ;  PURPOSE:  Local procedure to place legends for
  86. ;            Venn Diagrams.
  87. ;
  88. pro PlaceVennLegend, xWinSize, yWinSize, nameC, nameA, nameB, $
  89.     CURRDEV = gID, COLORS = colors, FLIPFLAG = flipFlag
  90.     if (N_PARAMS() LE 2) then begin
  91.         RETURN
  92.     endif else begin
  93.  
  94.         WSET, gID
  95.         ;  Compute handy offset values.
  96.         ;
  97.         fivPerX = ROUND(xWinSize / 20.0)
  98.         fivPerY = ROUND(yWinSize / 20.0)
  99.         tenPerX = 2 * fivPerX
  100.         tenPerY = 2 * fivPerY
  101.  
  102.         ;  Name swap if necessary
  103.         ;
  104.         if ((flipFlag) and (N_PARAMS() EQ 5)) then begin
  105.             ; Swap the names.
  106.             ;
  107.             tmp = nameA
  108.             nameA = nameB
  109.             nameB = tmp
  110.         endif
  111.  
  112.         if (N_PARAMS() EQ 5) then begin
  113.  
  114.             ;  Three items needed in legend.
  115.             ;  Create legend for result (C) set.
  116.             ;
  117.             xFill1 = [fivPerX,tenPerX,tenPerX,fivPerX]
  118.             yFill1 = [fivPerY,fivPerY,tenPerY,tenPerY] - 4
  119.             POLYFILL, xFill1, yFill1, /DEVICE, COLOR = colors[0]
  120.             XYOUTS, 2*fivPerX+4, fivPerY, /DEVICE, COLOR = colors[3], $
  121.                 'Set ' + nameC
  122.  
  123.             ;  Create legend for first (A) set.
  124.             ;
  125.             xFill2 = 3 * tenPerX + fivPerX + xFill1
  126.             POLYFILL, xFill2, yFill1, /DEVICE, COLOR=colors[1]
  127.             XYOUTS, 4 * tenPerX + fivPerX + 4, fivPerY, /DEVICE, $
  128.                 COLOR=colors[3], 'Set ' + nameA
  129.  
  130.             ;  Create legend for second (B) set.
  131.             ;
  132.             xFill3 = 7 * tenPerX + xFill1
  133.             POLYFILL, xFill3, yFill1, /DEVICE, COLOR = colors[2]
  134.             XYOUTS, 8 * tenPerX + 4, fivPerY, /DEVICE, $
  135.                 COLOR = colors[3], 'Set ' + nameB
  136.  
  137.         endif else if (N_PARAMS() EQ 3) then begin
  138.  
  139.             ; One item needed in legend.
  140.             ; Create legend for result (C) set.
  141.             ;
  142.             xFill1 = [fivPerX,tenPerX,tenPerX,fivPerX]
  143.             yFill1 = [fivPerY,fivPerY,tenPerY,tenPerY] - 4
  144.             POLYFILL, xFill1, yFill1, /DEVICE, COLOR=colors[0]
  145.             XYOUTS, 2*fivPerX+4, fivPerY, /DEVICE, COLOR=colors[3], $
  146.                 'Set ' + nameC
  147.  
  148.         endif
  149.  
  150.     endelse
  151.  
  152. end
  153.  
  154. ;----------------------------------------------------------------------------
  155. ;
  156. ;  PURPOSE:  Plot a Venn Diagram.
  157. ;            In this procedure, circular areas are used
  158. ;            to show the relative number of unique set members
  159. ;            in the incoming sets sA and sB.  Intersection
  160. ;            areas are show proportionately as circular secant
  161. ;            sectors where the shaded area indicates the amount
  162. ;            of sC shared between sA and sB.
  163. ;
  164. pro DrawVennDiagram, $
  165.     sA, sB, sC, $          ; IN: sets A, B, and C
  166.     nameA, nameB, nameC, $ ; IN: names of sets A, B, and C
  167.     opString, $            ; IN: operation string(Substraction, etc..)
  168.     gID, $                 ; IN: Window (graphics) ID
  169.     COLORS = colors
  170.  
  171.     ; In this procedure, circular areas are used to show the relative number
  172.     ; of unique set members in the incoming sets sA and sB.  Intersection
  173.     ; areas are show proportionately as circular secant sectors where the
  174.     ; shaded area indicates the amount of sC shared between sA and sB.
  175.     ;
  176.     ; Error catching, return to previous function.
  177.     ;
  178.     ;    ON_ERROR, 2
  179.  
  180.  
  181.     ;  Check on the number of parameters, must have full set.
  182.     ;
  183.     if (N_PARAMS() ne 8) then $
  184.         MESSAGE, 'ERROR: DrawVennDiagram requires 8 positional paramaters.'
  185.  
  186.     ;  Set the current window to the graphics display.
  187.     ;
  188.     WSET, gID
  189.     ERASE
  190.     xWinSize = !D.X_SIZE  ; Get display window x-size
  191.     yWinSize = !D.Y_SIZE  ;       ..           y-size
  192.  
  193.     ;  Set a flag to keep track of the larger of the 2 circles in display.
  194.     ;  Open a pixmap window to store the image to be "flipped."
  195.     ;
  196.     if (sA gt sB) then $
  197.         flipFlag = 0 $
  198.     else $
  199.         flipFlag = 1
  200.  
  201.     ;  Look for sets which were loaded by the user or the program
  202.     ;  at the start.
  203.     ;
  204.     if opString EQ '' then begin
  205.         r1 = .30 * (xWinSize < yWinSize)
  206.         xoff = (xWinSize - 2*r1) / 2
  207.         yoff = (yWinSize - 2*r1) / 2
  208.  
  209.         ; Create appropriate polygons for display (sets A and B; circles).      .
  210.         ;
  211.         thetas1 = INDGEN(201) * !PI * 2.0 / 200.0
  212.         ax = r1 * COS(thetas1) + r1 + xoff
  213.         ay = r1 * SIN(thetas1) + r1 + yoff
  214.         POLYFILL, ax, ay, /DEVICE, COLOR = colors[0]
  215.         PlaceVennLegend, xWinSize, yWinSize, nameC, $
  216.             currDev = gID, COLORS = colors, FLIPFLAG = flipFlag
  217.         RETURN
  218.     endif
  219.  
  220.     ;  Look for operations which result in the Empty Set.
  221.     ;
  222.     if (sC EQ 0) then begin
  223.         mtString = 'OPERATION PRODUCED THE EMPTY SET'
  224.         mtStringLength = STRLEN(mtString)
  225.         mtX = ROUND((xWinSize - $
  226.         FLOAT(mtStringLength * !D.X_CH_SIZE)) / 2.0)
  227.         mtY = ROUND((yWinSize - FLOAT(!D.Y_CH_SIZE)) / 2.0)
  228.         mtX = 10 ;Ten pixel offset.
  229.         XYOUTS, mtX, mtY, mtString, /DEVICE, COLOR = colors[3]
  230.         return
  231.     endif
  232.  
  233.     ;  If one of the two operators is the Empty Set then do not draw a Venn.
  234.     ;
  235.     if ((sA EQ 0) or (sB EQ 0)) then begin
  236.         mtString = 'NO VENN DIAGRAM FOR THIS SET'
  237.         mtStringLength = STRLEN(mtString)
  238.         mtX = ROUND((xWinSize - $
  239.             FLOAT(mtStringLength * !D.X_CH_SIZE)) / 2.0)
  240.         mtY = ROUND((yWinSize - FLOAT(!D.Y_CH_SIZE)) / 2.0)
  241.         mtX = 10 ;Ten pixel offset.
  242.         XYOUTS, mtX, mtY, mtString, /DEVICE, COLOR = colors[3]
  243.         return
  244.     endif
  245.  
  246.  
  247.     ;  Determine the controlling display diameter (in the y-direction) or the
  248.     ;  controlling sum of the diameters (in the x-direction) to scale the
  249.     ;  display.  Venn "circles" are plotted side-by-side in x-direction.
  250.     ;
  251.     smallSet = sA < sB ;smaller of the two incoming sets
  252.     largeSet = sA > sB ;larger    ..
  253.  
  254.     ;  Use either 80 percent of the xWinSize or 60 percent of the yWinSize.
  255.     ;  The y-direction is reduced to leave room for the legend.
  256.     ;
  257.     r1 = (0.4 * xWinSize - SQRT(sB/!PI)) < (0.30 * yWinSize)
  258.     area1 = !PI * r1^2
  259.     area2 = area1 * smallSet / largeSet
  260.     r2 = SQRT(area2 / !PI)
  261.  
  262.     ;  Set up a distance (between the circle centerpoints) variable for use
  263.     ;  in all cases.
  264.     ;
  265.     b = 0.0
  266.  
  267.     ;  For all operations, INTERSECTION, SUBTRACTION and UNION,
  268.     ;  create an overlay of the circles if sC is not equal to zero.
  269.     ;
  270.     ;  Determine the polygons associated with the area ratios based on the
  271.     ;  intersection of sets A and B (sA and sB).  The formula is nonlinear so
  272.     ;  use an incremental solution.
  273.     ;
  274.     ;  Calculate Intersecting area.
  275.     ;
  276.     case (STRUPCASE(opString)) of
  277.         'INTERSECTION' : sI = sC
  278.         'SUBTRACTION'  : sI = sA - sC
  279.         'UNION'        : sI = sA + sB - sC
  280.     endcase
  281.  
  282.     realFrac = FLOAT(sI) / largeSet
  283.     frac = 0.0
  284.     a = 0.0
  285.     while (frac lt realFrac) do begin
  286.  
  287.         a = a + 0.1 ;increment
  288.         b = r1 + r2 - a ;distance between center points of sA and sB circles
  289.  
  290.         if (ABS(b) ge 10.0^(-4)) then $
  291.  
  292.             ;  Local intersection x coordinate
  293.             ;
  294.             x1 = (b^2 + r1^2 - r2^2) / (2.0 * b) $
  295.         else begin
  296.  
  297.             ;  Limit case
  298.             ;
  299.             x1 = (b + r1^2 - r2^2) / 2.0
  300.         endelse
  301.         y1 = SQRT((r1^2 - x1^2) > 0.0)    ;local intersection y coordinate
  302.  
  303.         theta1 = ASIN((y1 / r1) < 1.0) ;angle to intersect of circs (large)
  304.         theta2 = ASIN((y1 / r2) < 1.0) ;angle to intersect of circs (small)
  305.  
  306.         ;  Determine fractional areas of overlayed circles (summation of the
  307.         ;  areas of the 2 secant circular sectors).
  308.         ;
  309.         p1 = r1^2 * theta1 - x1 * y1
  310.         if x1 lt b then $
  311.             p2 = r2^2 * theta2 - ((b-x1) * y1) $
  312.         else $
  313.             p2 = r2^2 * (!PI - theta2) + ((x1-b) * y1)
  314.  
  315.         areaI = p1 + p2
  316.         frac = areaI / area1
  317.  
  318.     endwhile
  319.  
  320.     ;  Set current graphics ID to passed-in value.
  321.     ;
  322.     WSET, gID
  323.  
  324.     ;  Begin testing for display types (two circles/two partially overlayed
  325.     ;  circles/two fully overlayed circles/single circle).
  326.     ;
  327.     ; No overlay
  328.     ;
  329.     if (sI EQ 0) then begin
  330.  
  331.         xoff = FIX((xWinSize - 2.0 * r1 - 2.0 * r2) / 4.0)
  332.         yoff = FIX((yWinSize - 2.0 * r1) / 2.0)
  333.         noSkip = 1 ; Go ahead and draw circles unless this changes.
  334.  
  335.         ;  Create appropriate polygons for display (sets A and B; circles).
  336.         ;
  337.         thetas1 = INDGEN(201) * !PI * 2.0 / 200.0
  338.         ax = r1 * COS(thetas1) + r1 + xoff
  339.         ay = r1 * SIN(thetas1) + r1 + yoff
  340.         bx = r2 * COS(thetas1) + xWinSize - xoff - r2
  341.         by = r2 * SIN(thetas1) + r1 + yoff
  342.  
  343.         if (flipFlag) then begin
  344.             ax = xWinSize - ax
  345.             bx = xWinSize - bx
  346.         endif
  347.  
  348.         case (STRUPCASE(opString)) of
  349.  
  350.             'INTERSECTION' : begin
  351.                 ; Create a warning string for the empty set.
  352.                 ;
  353.                 mtString = 'OPERATION PRODUCED THE EMPTY SET'
  354.                 mtStringLength = STRLEN(mtString)
  355.                 mtX = ROUND((xWinSize - $
  356.                     FLOAT(mtStringLength * !D.X_CH_SIZE)) / 2.0)
  357.                 mtY = ROUND((yWinSize - FLOAT(!D.Y_CH_SIZE)) / 2.0)
  358.                 mtX = 10 ;Ten pixel offset
  359.                 XYOUTS, mtX, mtY, mtString, /DEVICE, COLOR = colors[0]
  360.                 noSkip = 0 ;Skip plotting circles.
  361.             end
  362.  
  363.             'SUBTRACTION' : begin
  364.                 if (flipFlag) then $
  365.                     POLYFILL, bx, by, /DEVICE, COLOR = colors[0] $
  366.                 else $
  367.                     POLYFILL, ax, ay, /DEVICE, COLOR = colors[0]
  368.             end
  369.  
  370.             'UNION' : begin
  371.                 POLYFILL, ax, ay, /DEVICE, COLOR = colors[0]
  372.                 POLYFILL, bx, by, /DEVICE, COLOR = colors[0]
  373.             end
  374.  
  375.         endcase
  376.  
  377.         if (noSkip) then begin
  378.             position = [xoff,yoff,2 * r1 + xoff,2 * r1 + yoff]
  379.             if (flipFlag) then begin
  380.                 temp = position[0]
  381.                 position[0] = xWinSize - position[2]
  382.                 position[2] = xWinSize - temp
  383.             endif
  384.             PlotCircle, r1, position, /NOERASE, COLOR = colors[1]
  385.             xl = xWinSize - xoff - 2.0 * r2
  386.             xr = xl + 2.0 * r2
  387.             position = [xl, yoff + r1 - r2, $
  388.                     xr, yoff + r1 + r2]
  389.             if (flipFlag) then begin
  390.                 temp = position[0]
  391.                 position[0] = xWinSize - position[2]
  392.                 position[2] = xWinSize - temp
  393.             endif
  394.             PlotCircle, r2, position, /NOERASE, COLOR = colors[2]
  395.         endif
  396.  
  397.     ;  2 partially overlayed.
  398.     ;
  399.     endif else if ((sI gt 0) and (sI lt (sA < sB))) then begin
  400.  
  401.         xoff = FIX((xWinSize - r1 - r2 - b) / 2.0)
  402.         yoff = FIX((yWinSize - 2.0 * r1) / 2.0)
  403.  
  404.         ;  Create appropriate polygons for display (sets A and B circles
  405.         ;  minus their respective intersection polygon).
  406.         ;
  407.  
  408.         thetas1 = INDGEN(201) * theta1 * 2.0 / 200.0 - theta1
  409.         xa = r1 * COS(thetas1) + r1
  410.         ya = r1 * SIN(thetas1) + r1
  411.  
  412.         if (b gt x1) then $
  413.                thetas2 = INDGEN(201) * theta2 * 2.0 / 200.0 - theta2 $
  414.            else $
  415.                thetas2 = INDGEN(201) * (!PI - theta2) * 2.0 / 200.0 $
  416.                    - (!PI - theta2)
  417.         xb = -r2 * COS(thetas2) + b + r1
  418.         yb =  r2 * SIN(thetas2) + r1
  419.  
  420.         thetas3 = INDGEN(201) * (2.0 * !PI - 2.0 * theta1) / 200.0 + $
  421.             theta1
  422.         xc = r1 * COS(thetas3) + r1
  423.         yc = r1 * SIN(thetas3) + r1
  424.         if (b gt x1) then $
  425.                thetas4 = INDGEN(201) * (2.0 * !PI - 2.0 * theta2) / 200.0 + $
  426.                    theta2 $
  427.            else $
  428.                thetas4 = INDGEN(201) * (2.0 * !PI - 2.0 * (!PI - theta2)) $
  429.                    / 200.0 + (!PI - theta2)
  430.  
  431.         xd = -r2 * COS(thetas4) + b + r1
  432.         yd =  r2 * SIN(thetas4) + r1
  433.  
  434.         ix = [REVERSE(xa),xb] + xoff
  435.         iy = [REVERSE(ya),yb] + yoff
  436.  
  437.         ax = [xc,xb] + xoff
  438.         ay = [yc,yb] + yoff
  439.         bx = [xd,xa] + xoff
  440.         by = [yd,ya] + yoff
  441.         if (flipFlag) then begin
  442.             ax = xWinSize - ax
  443.             bx = xWinSize - bx
  444.             ix = xWinSize - ix
  445.         endif
  446.  
  447.         case STRUPCASE(opString) of
  448.  
  449.             'INTERSECTION' : begin
  450.                 POLYFILL, ix, iy, /DEVICE, COLOR=colors[0]
  451.             end
  452.  
  453.             'SUBTRACTION' : begin
  454.                 if (flipFlag) then $
  455.                     POLYFILL, bx, by, /DEVICE, COLOR=colors[0] $
  456.                 else $
  457.                     POLYFILL, ax, ay, /DEVICE, COLOR=colors[0]
  458.             end
  459.  
  460.             'UNION' : begin
  461.                 POLYFILL, ix, iy, /DEVICE, COLOR = colors[0]
  462.                 POLYFILL, ax, ay, /DEVICE, COLOR = colors[0]
  463.  
  464.                 POLYFILL, bx, by, /DEVICE, COLOR = colors[0]
  465.             end
  466.  
  467.         endcase
  468.  
  469.         position = [xoff,yoff,2 * r1 + xoff,2 * r1 + yoff]
  470.         if (flipFlag) then begin
  471.             temp = position[0]
  472.             position[0] = xWinSize - position[2]
  473.             position[2] = xWinSize - temp
  474.         endif
  475.         PlotCircle, r1, position, /NOERASE, COLOR=colors[1]
  476.  
  477.         position = [xoff + b + r1 - r2,yoff + r1 - r2, $
  478.                     xoff + b + r1 + r2,yoff + r1 + r2]
  479.         if (flipFlag) then begin
  480.             temp = position[0]
  481.             position[0] = xWinSize - position[2]
  482.             position[2] = xWinSize - temp
  483.         endif
  484.  
  485.         PlotCircle, r2, position, /NOERASE, COLOR=colors[2]
  486.  
  487.     endif else if (sI EQ (sA < sB)) then begin
  488.  
  489.         xoff = FIX((xWinSize - 2.0 * r1) / 2.0)
  490.         yoff = FIX((yWinSize - 2.0 * r1) / 2.0)
  491.         noSkip = 1 ; Go ahead and draw circles unless this changes.
  492.  
  493.         ;  Create appropriate polygons for display (sets A and B; circles).
  494.         ;
  495.         thetas1 = INDGEN(201) * !PI * 2.0 / 200.0
  496.         ax = r1 * COS(thetas1) + r1 + xoff
  497.         ay = r1 * SIN(thetas1) + r1 + yoff
  498.         bx = r2 * COS(thetas1) + r1 + xoff + (r1 - r2) / 2.0
  499.         by = r2 * SIN(thetas1) + r1 + yoff
  500.         if (flipFlag) then begin
  501.             ax = xWinSize - ax
  502.             bx = xWinSize - bx
  503.         endif
  504.  
  505.  
  506.         case (STRUPCASE(opString)) of
  507.  
  508.             'INTERSECTION' : begin
  509.                 POLYFILL, bx, by, /DEVICE, COLOR=colors[0]
  510.             end
  511.  
  512.             'SUBTRACTION' : begin
  513.                 if (flipFlag) then begin
  514.                     ; Create a warning string for the empty set.
  515.                     ;
  516.                     mtString = 'OPERATION PRODUCED THE EMPTY SET'
  517.                     mtStringLength = STRLEN(mtString)
  518.                     mtX = ROUND((xWinSize - $
  519.                         FLOAT(mtStringLength * !D.X_CH_SIZE)) / 2.0)
  520.                     mtY = ROUND((yWinSize - FLOAT(!D.Y_CH_SIZE)) / 2.0)
  521.                     mtX = 10 ;Ten pixel offset
  522.                     XYOUTS, mtX, mtY, mtString, /DEVICE, COLOR = colors[3]
  523.                     noSkip = 0 ;Skip plotting circles.
  524.                 endif else begin
  525.                     POLYFILL, ax, ay, /DEVICE, COLOR = colors[0]
  526.                     POLYFILL, bx, by, /DEVICE, COLOR = !P.BACKGROUND
  527.                 endelse
  528.             end
  529.  
  530.             'UNION' : begin
  531.                 POLYFILL, ax, ay, /DEVICE, COLOR=colors[0]
  532.                 POLYFILL, bx, by, /DEVICE, COLOR=colors[0]
  533.             end
  534.  
  535.         endcase
  536.  
  537.         if (noSkip) then begin
  538.             position = [xoff,yoff,2 * r1 + xoff,2 * r1 + yoff]
  539.             if (flipFlag) then begin
  540.                 temp = position[0]
  541.                 position[0] = xWinSize - position[2]
  542.                 position[2] = xWinSize - temp
  543.             endif
  544.  
  545.             PlotCircle, r1, position, /NOERASE, COLOR=colors[1]
  546.             xl = xoff + 3.0 * (r1 - r2) / 2.0
  547.             xr = xl + 2.0 * r2
  548.             position = [xl, yoff + r1 - r2, $
  549.                    xr, yoff + r1 + r2]
  550.             if (flipFlag) then begin
  551.                 temp = position[0]
  552.                 position[0] = xWinSize - position[2]
  553.                 position[2] = xWinSize - temp
  554.             endif
  555.  
  556.             PlotCircle, r2, position, /NOERASE, COLOR = colors[2]
  557.         endif
  558.  
  559.     endif else if ((sI EQ sA) and (sI EQ sB)) then begin
  560.  
  561.         xoff = FIX((xWinSize - 2.0 * r1) / 2.0)
  562.         yoff = FIX((yWinSize - 2.0 * r1) / 2.0)
  563.  
  564.         ;  Create appropriate polygons for display (sets A and B; circles).
  565.         ;
  566.         thetas1 = INDGEN(201) * !PI * 2.0 / 200.0
  567.         ax = r1 * COS(thetas1) + r1 + xoff
  568.         ay = r1 * SIN(thetas1) + r1 + yoff
  569.         if (flipFlag) then begin
  570.             ax = xWinSize - ax
  571.         endif
  572.  
  573.  
  574.         case (STRUPCASE(opString)) of
  575.  
  576.             'INTERSECTION' : begin
  577.                 POLYFILL, ax, ay, /DEVICE, COLOR=colors[0]
  578.             end
  579.  
  580.             'SUBTRACTION' : begin
  581.                 ; Create a warning string for the empty set.
  582.                 ;
  583.                 mtString = 'OPERATION PRODUCED THE EMPTY SET'
  584.                 mtStringLength = STRLEN(mtString)
  585.                 mtX = ROUND((xWinSize - $
  586.                     FLOAT(mtStringLength * !D.X_CH_SIZE)) / 2.0)
  587.                 mtY = ROUND((yWinSize - FLOAT(!D.Y_CH_SIZE)) / 2.0)
  588.                 mtX = 10 ;Ten pixel offset.
  589.                 XYOUTS, mtX, mtY, mtString, /DEVICE, COLOR = colors[3]
  590.                 noSkip = 0 ;Skip plotting circles.
  591.             end
  592.  
  593.             'UNION' : begin
  594.                 POLYFILL, ax, ay, /DEVICE, COLOR=colors[0]
  595.             end
  596.  
  597.  
  598.         endcase
  599.  
  600.         if (noSkip) then begin
  601.             position = [xoff,yoff,2 * r1 + xoff,2 * r1 + yoff]
  602.  
  603.             if (flipFlag) then begin
  604.                 temp = position[0]
  605.                 position[0] = xWinSize - position[2]
  606.                 position[2] = xWinSize - temp
  607.             endif
  608.  
  609.             PlotCircle, r1, position, /NOERASE, COLOR=colors[1]
  610.         endif
  611.  
  612.     endif
  613.  
  614.     ;  Display total Venn legend if procedure makes it to this point.
  615.     ;
  616.     PlaceVennLegend, xWinSize, yWinSize, nameC, nameA, nameB, $
  617.         currDev = gID, COLORS = colors, FLIPFLAG = flipFlag
  618.  
  619.  
  620. end
  621.  
  622. ;----------------------------------------------------------------------------
  623. ;
  624. ;  PURPOSE: Obtain the intersection of two sets.
  625. ;
  626. function SetsIntersect, origA, origB, delta, Count = count , $
  627.                        Digits = digits, Factor = factor
  628.  
  629.   if N_PARAMS() lt 2 then $
  630.     MESSAGE, "Requires two arguments"
  631.   if N_PARAMS() eq 2 then $
  632.     delta = 0 $
  633.   else $
  634.      if delta LT 0 then $
  635.     MESSAGE, "DELTA must be >= zero"
  636.  
  637.     ; Handle EMPTY set as argument
  638.     ;
  639.     if ((N_ELEMENTS(origA) eq 0) or (N_ELEMENTS(origB) eq 0)) then begin
  640.         count = 0
  641.           return, -1
  642.     endif
  643.  
  644. ; Determine Datatype of A and B arrays and force them to be 1D arrays if necessary.
  645. ; Also create copies of the original inputs.
  646.   dimA = (Size(origA))[0]
  647.   dimB = (Size(origB))[0]
  648.   if (dimA eq 0) then $
  649.       a = REPLICATE(origA, 1) $
  650.   else if (dimA gt 1) then $
  651.       a = REFORM(origA, N_ELEMENTS(origA)) $
  652.   else $
  653.       a = origA
  654.  
  655.   if (dimB eq 0) then $
  656.       b = REPLICATE(origB, 1) $
  657.   else if (dimB gt 1) then $
  658.       b = REFORM(origB, N_ELEMENTS(origB)) $
  659.    else $
  660.       b = origB
  661.  
  662.   dtA = (Size(origA))[2]
  663.   dtB = (Size(origB))[2]
  664.  
  665.  
  666.  
  667.   idelta = delta
  668.   factor = 1
  669.  
  670.   if ((dtA ge 4) or (dtB ge 4)) then begin  ; Float?
  671.  
  672.     if (idelta ne 0) then begin
  673. ; Determine the scale factor needed to convert floats to integers.
  674.       idelta = idelta* factor
  675.       while ((idelta) - FIX(idelta)) ne 0 do begin
  676.         factor = factor * 10.
  677.         if factor eq 1e8 then $
  678.            MESSAGE, 'Too many significant digits'
  679.         idelta = delta * factor    ; Determine the integer-based DELTA
  680.       endwhile
  681.  
  682.       idelta = Fix(idelta)
  683.     endif
  684.  
  685.     if Keyword_Set(digits) then begin
  686.       if digits ge 8 then $
  687.          Message, 'Too many significant digits'
  688.       if (10. * digits) gt factor  then begin
  689.            factor = 10. ^ digits
  690.            idelta = factor * delta
  691.       endif
  692.       Help,idelta, factor
  693.     endif else if idelta eq 0 then  begin
  694.       factor = 1000.
  695.       idelta = factor*delta
  696.       Help,idelta, factor
  697.     endif
  698.  
  699. ; Create integer versions of A and B
  700.     a = ROUND(TEMPORARY(a) * factor)
  701.     ;Help,a
  702.     b = ROUND(TEMPORARY(b) * factor)
  703.   endif else begin  ; Byte or Integers
  704.     if ((idelta) - Fix(idelta)) ne 0 then $
  705.       Message, 'DELTA must be an integer when A and B are not of type FLOAT or DOUBLE'
  706.   endelse
  707.  
  708.   offset = (MIN(a) - idelta) < MIN(b)
  709.   num = ((MAX(a) + idelta) > MAX(b)) - offset + 1
  710.   a = TEMPORARY(a) - offset
  711.  
  712. ; Create a mask image based on A
  713.   maskA = BYTARR(num)
  714.   maskA[a] = 1B
  715.  
  716. ; Create expanded mask based on DELTA
  717.   if idelta gt 0 then begin
  718.     minMaskA = SHIFT(maskA, -1 * idelta)
  719.     maxMaskA = SHIFT(maskA, idelta)
  720.     maskA    = TEMPORARY(maskA) or TEMPORARY(minMaskA) or $
  721.                  TEMPORARY(maxMaskA)
  722.     maskA    = not(TEMPORARY(maskA)) - 254B
  723.     s = BYTARR(idelta) + 1B
  724.     maskA  = DILATE(ERODE(TEMPORARY(maskA), s), s)
  725.     s = 0B
  726.     maskA  = not( TEMPORARY(maskA)) - 254B
  727.   endif
  728.  
  729.   maskB = BYTARR(num)
  730.   b = TEMPORARY(b) - offset
  731.   maskB[b] = 1B
  732.   both   = TEMPORARY(maskA) * TEMPORARY(maskB)
  733.   match = WHERE(both eq 1, count)
  734.   if count gt 0 then begin
  735.     result = DOUBLE(match + offset) / factor
  736.     case dtB of
  737.       1: return, BYTE(result)
  738.       2: return, FIX(result)
  739.       3: return, LONG(result)
  740.       4: return, FLOAT(result)
  741.       5: return, result
  742.     endcase
  743.   endif else begin
  744.     return, -1
  745.   endelse
  746. end
  747.  
  748.  
  749. ;----------------------------------------------------------------------------
  750. ;
  751. ;  PURPOSE: Obtain the subtraction of two sets.
  752. ;
  753. function SetsSubtract, origA, origB, delta, Count = count , Digits = digits, Intersect_Size = iSize
  754.  
  755.   if N_PARAMS() lt 2 then $
  756.     Message, "Requires two arguments"
  757.   if N_PARAMS() eq 2 then $
  758.     delta = 0 $
  759.   else $
  760.      if delta lt 0 then $
  761.     MESSAGE, "DELTA must be >= zero"
  762.  
  763.  
  764.  
  765.   if (N_ELEMENTS(origA) eq 0) then begin
  766.       count = 0
  767.       return, -1
  768.   endif
  769.  
  770. ; Determine Datatype of A and B arrays and force them to be 1D arrays if necessary.
  771. ; Also create copies of the original inputs.
  772.   dimA = (SIZE(origA))[0]
  773.  
  774.   if (dimA eq 0) then $
  775.       a = REPLICATE(origA, 1) $
  776.   else if (dimA gt 1) then $
  777.       a = REFORM(origA, N_ELEMENTS(origA)) $
  778.   else $
  779.       a = origA
  780.  
  781.   dtA = (SIZE(origA))[2]
  782.  
  783.   if (N_ELEMENTS(origB) eq 0) then begin
  784.       count = N_Elements(a)
  785.       return, a
  786.   endif
  787.  
  788. ; Find Intersection of A and B
  789.   c = SetsIntersect(origB, a, delta, Count = iSize, Digits = digits, $
  790.                          Factor = factor)
  791.  
  792.   if iSize ne 0 then begin  ; Common elements?
  793.  
  794. ; Create integer versions of A and C
  795.     a = ROUND(TEMPORARY(a) * factor)
  796.     c = ROUND(TEMPORARY(c) * factor)
  797.  
  798.     offset = MIN(a) < MIN(c)
  799.     num = (MAX(a) > MAX(c)) - offset + 1
  800.     a = TEMPORARY(a) - offset
  801.  
  802. ; Create a mask images based on A and C
  803.     maskA = BYTARR(num)
  804.     maskA[a] = 1B
  805.     maskC = BYTARR(num) + 1
  806.     c = TEMPORARY(c) - offset
  807.     maskC[c] = 0B
  808.     both   = TEMPORARY(maskA) * TEMPORARY(maskC)
  809.     match = Where(both EQ 1, count)
  810.  
  811.     if (count gt 0) then begin
  812.       result = DOUBLE(match + offset) / factor
  813.       case dtA of
  814.         1: return, BYTE(result)
  815.         2: return, FIX(result)
  816.         3: return, LONG(result)
  817.         4: return, FLOAT(result)
  818.         5: return, result
  819.       endcase
  820.     endif else begin
  821.       return, -1
  822.     endelse
  823.   endif
  824.   count = N_ELEMENTS(a)
  825.   return, a
  826. end
  827.  
  828.  
  829. ;----------------------------------------------------------------------------
  830. ;
  831. ;  PURPOSE: Obtain the union of two sets.
  832. ;
  833. function SetsUnion, origA, origB, delta, Count = count , Digits = digits, Intersect_Size = iSize
  834.  
  835.   if (N_PARAMS() lt 2) then $
  836.     Message, "Requires two arguments"
  837.   if (N_PARAMS() eq 2) then $
  838.     delta = 0 $
  839.   else $
  840.      if (delta lt 0) then $
  841.     Message, "DELTA must be >= zero"
  842.   if ((N_ELEMENTS(origA) eq 0) and (N_ELEMENTS(origB) eq 0)) then begin
  843.     iSize = 0
  844.       count = 0
  845.       return, -1
  846.   endif
  847.  
  848.   if (N_ELEMENTS(origA) eq 0) then begin ; Only one valid set, return it to caller.
  849.  
  850.   ; Determine Datatype of A and B arrays and force them to be 1D arrays if necessary.
  851.   ; Also create copies of the original inputs.
  852.     dimB = (Size(origB))[0]
  853.  
  854.     if (dimB eq 0) then $
  855.         b = REPLICATE(origB, 1) $
  856.     else if (dimB gt 1) then $
  857.         b = REFORM(origB, N_ELEMENTS(origB)) $
  858.     else $
  859.         b = origB
  860.     dtB = (Size(origB))[2]
  861.  
  862.       count = N_Elements(origB)
  863.       iSize = 0
  864.       return, b
  865.   endif
  866.  
  867.   if (N_ELEMENTS(origB) eq 0) then begin ; Only one valid set, return it to caller.
  868.     dimA = (Size(origA))[0]
  869.     if (dimA eq 0) then $
  870.         a = REPLICATE(origA, 1) $
  871.     else if (dimA gt 1) then $
  872.         a = REFORM(origA, N_ELEMENTS(origA)) $
  873.     else $
  874.         a = origA
  875.       dtA = (Size(origA))[2]
  876.  
  877.       count = N_Elements(origA)
  878.       iSize = 0
  879.       return, a
  880.   endif
  881.  
  882.   dimA = (Size(origA))[0]
  883.   if (dimA eq 0) then $
  884.     a = REPLICATE(origA, 1) $
  885.   else if (dimA gt 1) then $
  886.       a = REFORM(origA, N_ELEMENTS(origA)) $
  887.   else $
  888.       a = origA
  889.   dtA = (Size(origA))[2]
  890.   dimB = (Size(origB))[0]
  891.   if (dimB eq 0) then $
  892.         b = REPLICATE(origB, 1) $
  893.     else if (dimB gt 1) then $
  894.         b = REFORM(origB, N_ELEMENTS(origB)) $
  895.     else $
  896.         b = origB
  897.     dtB = (Size(origB))[2]
  898.  
  899. ; Find Intersection of A and B
  900.   c = SetsIntersect(origB, a, delta, Count = iSize, Digits = digits, $
  901.                          Factor = factor)
  902.   if (delta ne 0) then begin
  903.  
  904.   if (iSize ne 0) then begin  ; Common elements?
  905.  
  906. ; Create integer versions of A and B
  907.     a = ROUND(TEMPORARY(a) * factor)
  908.     ;Help,a
  909.     c = ROUND(TEMPORARY(c) * factor)
  910.  
  911.     offset = MIN(a) < MIN(c)
  912.  ; Print, offset
  913.     num = (MAX(a) > MAX(c)) - offset + 1
  914.     a = TEMPORARY(a) - offset
  915.  
  916. ; Create mask images based on A and C
  917.     maskA = BYTARR(num)
  918.     maskA[a] = 1B
  919.     maskC = BYTARR(num) + 1
  920.     c = TEMPORARY(c) - offset
  921.     maskC[c] = 0B
  922.     both   = TEMPORARY(maskA) * TEMPORARY(maskC)
  923.     match = WHERE(both eq 1, count)
  924.     if count gt 0 then $
  925.       result = DOUBLE(match + offset) / factor
  926.   endif
  927.   endif else begin
  928.  
  929.     result = [REFORM(a,N_ELEMENTS(a)), REFORM(b, N_ELEMENTS(b))]
  930.     result = result[UNIQ(result, SORT(result))]
  931.     count = N_ELEMENTS(result)
  932.   endelse
  933.     if count gt 0 then begin
  934.  
  935.    ; Print, 'Data Type B: ', dtB
  936.       case dtB of
  937.         1: return, BYTE(result)
  938.         2: return, FIX(result)
  939.         3: return, LONG(result)
  940.         4: return, FLOAT(result)
  941.         5: return, result
  942.       endcase
  943.     endif else begin
  944.       return, -1
  945.     endelse
  946.  
  947.   return, a
  948. end
  949. ;----------------------------------------------------------------------------
  950. ;
  951. ;  PURPOSE: Quit this application.
  952. ;
  953. pro DataViewerHandler, $
  954.     sEvent             ; IN: event structure
  955.  
  956.     WIDGET_CONTROL, sEvent.top, /DESTROY
  957. end
  958.  
  959. ;----------------------------------------------------------------------------
  960. ;
  961. ;  PURPOSE: Widget program to display array data
  962. ;           within a table widget.
  963. ;
  964. function DataViewer, $
  965.     data, $                ; IN: Data to display.
  966.     TITLE = title, $       ; IN: Title fo the widget table
  967.     GROUP_LEADER = wGroup  ; IN: (opt) Group leader
  968.  
  969.     if (N_ELEMENTS(title) EQ 0) then $
  970.         title = ''
  971.     if (N_ELEMENTS(wGroup) EQ 0) then $
  972.            wGroup = 0L
  973.  
  974.     sizeData = N_ELEMENTS(data)    ; Determine # of data elements
  975.     if (sizeData EQ 0) then $      ; abort if there is no data.
  976.         RETURN, 0L
  977.     if (sizeData EQ 1) then $
  978.         tmpData = REPLICATE(STRTRIM(STRING(data)),1) $
  979.     else $
  980.         tmpData = STRTRIM(STRING(REFORM(data,sizeData,1)),2)
  981.  
  982.     ;  The data is to be displayed in a 7 column table widget.
  983.     ;  If needed, the data is padded with blanks to create a
  984.     ;  rectangular table which is compatible with IDL's table
  985.     ;  widget.
  986.     ;
  987.     cols = 7
  988.     rows = sizeData / cols
  989.     left = sizeData mod cols
  990.     if left GT 0 then begin
  991.         add = StrArr(cols-left)
  992.         tmpData = [tmpData,add]
  993.         tmpData = REFORM(tmpData, cols, rows+1)
  994.     endif else $
  995.         tmpData = REFORM(tmpData, cols, rows)
  996.  
  997.     ;  Create the Widget with a scrolling table widget depending on
  998.     ;  the number of rows.
  999.     ;
  1000.     wTLB = WIDGET_BASE(TITLE = title,$
  1001.         GROUP_LEADER = wGroup, /BASE_ALIGN_CENTER, /COLUMN)
  1002.     if (rows gt 8) then $
  1003.         wTable = WIDGET_TABLE(wTLB, VALUE = tmpData, /NO_HEADERS, XSIZE = cols, $
  1004.             /SCROLL) $
  1005.     else  $
  1006.         wTable = WIDGET_TABLE(wTLB, VALUE = tmpData, /NO_HEADERS, XSIZE = cols)
  1007.  
  1008.     wButton = WIDGET_BUTTON(wTLB, VALUE = 'Close')
  1009.  
  1010.     ;  Realize the Data Viewer and register the widget with XManager
  1011.     ;
  1012.     WIDGET_CONTROL, wTLB, /Realize
  1013.     XMANAGER, 'DataViewer: ' + title, wTLB, EVENT_HANDLER = 'DataViewerHandler', $
  1014.         /NO_BLOCK
  1015.  
  1016.     ;  Return the ID of the widget's top level base.
  1017.     ;
  1018.     RETURN, wTLB
  1019. end
  1020.  
  1021. ;----------------------------------------------------------------------------
  1022. ;
  1023. ;  PURPOSE: Determine the IDL data type of value.
  1024. ;
  1025. function TypeOf, $
  1026.     value   ; IN: value
  1027.  
  1028.     type = (SIZE(value))[(SIZE(value))[0]+1]
  1029.     case type of
  1030.         0: typeStr = 'undefined'
  1031.         1: typeStr = 'byte'
  1032.         2: typeStr = 'integer'
  1033.         3: typeStr = 'long integer'
  1034.         4: typeStr = 'float'
  1035.         5: typeStr = 'double'
  1036.         6: typeStr = 'complex'
  1037.         7: typeStr = 'double complex'
  1038.         8: typeStr = 'string'
  1039.      endcase
  1040.      RETURN, typeStr
  1041.  
  1042. end
  1043.  
  1044. ;----------------------------------------------------------------------------
  1045. ;
  1046. ;  PURPOSE:  Determine whether or not the set is compatible
  1047. ;            with the Venn Demo program.
  1048. ;
  1049. function ValidSetData, $
  1050.     set             ; IN: data set
  1051.  
  1052.     if ((TypeOf(set) EQ 'integer') OR $
  1053.         (TypeOf(set) EQ 'long integer') OR $
  1054.         (TypeOf(set) EQ 'byte')) then $
  1055.         RETURN, 1B $
  1056.     else $
  1057.         RETURN, 0B
  1058. end
  1059.  
  1060. ;----------------------------------------------------------------------------
  1061. ;
  1062. ;  PURPOSE:  Define the bitmaps buttons for the Set Calculator
  1063. ;
  1064. pro LoadCalcBitmaps, $
  1065.     bmDelete,  $    ; OUT: Delete button
  1066.     bmClear, $      ; OUT: Clear button
  1067.     bmIntersect, $  ; OUT: Intersect button
  1068.     bmUnion, $      ; OUT: Union button
  1069.     bmSubtract, $   ; OUT: Subtract button
  1070.     bmEnter         ; OUT: Enter button
  1071.  
  1072.     bmDelete = BYTE( $
  1073.         [[  0,   0,   0], [  0,   0,   0], [  0,   0,   0], $
  1074.          [  0,   0,   0], [128,   0,   0], [192,   0,   0], $
  1075.          [224,   0,   0], [240,   0,   0], [248, 255,   0], $
  1076.          [252, 255,   0], [248, 255,   0], [240,   0,   0], $
  1077.          [224,   0,   0], [192,   0,   0], [128,   0,   0], $
  1078.          [  0,   0,   0], [  0,   0,   0], [  0,   0,   0]])
  1079.  
  1080.     bmClear = BYTE( $
  1081.         [[  0,   0,   0], [  0,   0,   0], [  0,   0,   0], $
  1082.          [  0,   0,   0], [  0,   0,   0], [248, 124,   0], $
  1083.          [252, 124,   0], [ 12,  12,   0], [  6,  12,   0], $
  1084.          [  6, 124,   0], [  6, 124,   0], [  6,  12,   0], $
  1085.          [ 12,  12,   0], [252, 124,   0], [248, 124,   0], $
  1086.          [  0,   0,   0], [  0,   0,   0], [  0,   0,   0]])
  1087.  
  1088.      bmIntersect = BYTE( $
  1089.         [[  0,   0,   0], [  0,   0,   0], [  0,   0,   0], $
  1090.          [  0,   0,   0], [192,   7,   0], [224,  15,   0], $
  1091.          [112,  28,   0], [ 56,  56,   0], [ 24,  48,   0], $
  1092.          [ 24,  48,   0], [ 24,  48,   0], [ 24,  48,   0], $
  1093.          [ 24,  48,   0], [ 24,  48,   0], [ 24,  48,   0], $
  1094.          [  0,   0,   0], [  0,   0,   0], [  0,   0,   0]])
  1095.  
  1096.     bmUnion = BYTE( $
  1097.         [[  0,   0,   0], [  0,   0,   0], [  0,   0,   0], $
  1098.          [  0,   0,   0], [ 24,  48,   0], [ 24,  48,   0], $
  1099.          [ 24,  48,   0], [ 24,  48,   0], [ 24,  48,   0], $
  1100.          [ 24,  48,   0], [ 24,  48,   0], [ 24,  48,   0], $
  1101.          [ 56,  56,   0], [112,  28,   0], [ 224, 15,   0], $
  1102.          [192,   7,   0], [  0,   0,   0], [  0,   0,   0]])
  1103.  
  1104.     bmSubtract = BYTE( $
  1105.         [[  0,   0,   0], [  0,   0,   0], [  0,   0,   0], $
  1106.          [  0,   0,   0], [  0,   0,   0], [  0,   0,   0], $
  1107.          [  0,   0,   0], [  0,   0,   0], [252, 127,   0], $
  1108.          [252, 127,   0], [  0,   0,   0], [  0,   0,   0], $
  1109.          [  0,   0,   0], [  0,   0,   0], [  0,   0,   0], $
  1110.          [  0,   0,   0], [  0,   0,   0], [  0,   0,   0]])
  1111.  
  1112.     bmEnter = BYTE( $
  1113.         [[  0,   0,   0], [  0,   0,   0], [  0,   0,   0], $
  1114.          [  0,   0,   0], [  0,   0,   0], [  0,   0,   0], $
  1115.          [252, 127,   0], [252, 127,   0], [  0,   0,   0], $
  1116.          [  0,   0,   0], [252, 127,   0], [252, 127,   0], $
  1117.          [  0,   0,   0], [  0,   0,   0], [  0,   0,   0], $
  1118.          [  0,   0,   0], [  0,   0,   0], [  0,   0,   0]])
  1119. end
  1120.  
  1121. ;----------------------------------------------------------------------------
  1122. ;
  1123. ;  PURPOSE:  Creates an instance of the 'sets' class and
  1124. ;            and updates the Venn Demo GUI as needed.
  1125. ;
  1126. ;  Side Effects:  Creates a new 'sets' object,sensitizes a widget
  1127. ;                 button on the calculator GUI, and adds a menu item
  1128. ;                 to the 'View set data' menu.
  1129. ;
  1130. pro CreateSet, $
  1131.     wSetButton, $    ; IN: Set button ID
  1132.     wDataButton, $   ; IN: View Set Data menu button ID.
  1133.     numSets, $       ; IN/OUT: number of sets
  1134.     oSetList, $      ; IN/OUT: set array list
  1135.     setNames, $      ; IN/OUT: array list of set names
  1136.     DATA=data, $     ; IN: (opt) Data of the set
  1137.     SEED = seed      ; IN: (opt) Seed for random generation of data
  1138.  
  1139.     ; If no data is passed in then the set data will be generated
  1140.     ;
  1141.     if (N_ELEMENTS(data) EQ 0) then $
  1142.         data = FIX(RANDOMN(seed,(ROUND(RANDOMU(seed)*100)>1))*RANDOMU(seed)*100)
  1143.  
  1144.     numSets = numSets + 1
  1145.  
  1146.     ;  Create the set, sensitize the button on the Set Calculator, and
  1147.     ;  add the set to the 'View set data' menu.
  1148.     ;
  1149.     name = STRING(64B + BYTE(numSets))
  1150.     oSet = OBJ_NEW('sets', name, data)
  1151.     setNames[numSets-1] =  'Set ' + name
  1152.     oSetList[numSets-1] = oSet
  1153.     WIDGET_CONTROL, wSetButton, SENSITIVE = 1
  1154.     WIDGET_CONTROL, wDataButton, SENSITIVE = 1
  1155.  
  1156. end
  1157.  
  1158. ;----------------------------------------------------------------------------
  1159. ;
  1160. ;  PURPOSE:  This function calls the appropriate set operation routine.
  1161. ;            It performs :
  1162. ;
  1163. ;                   (Set A)  operation  (Set B)  = (Set C)
  1164. ;
  1165. ;            The resulting data (Set C), number of elements
  1166. ;            in the result, and the number of common elements is returned.
  1167. ;
  1168. function DoSetOp, $
  1169.     a, b, $                 ; IN: Sets A and B
  1170.     op, $                   ; IN: Set operator (intersect, subtract, or union)
  1171.     Count=count, $          ; OUT: (opt) number of data in set C
  1172.     Intersect_Size = iSize  ; OUT: (opt) size of set C
  1173.  
  1174.     FORWARD_FUNCTION SetsIntersect, SetsSubtract, SetsUnion
  1175.  
  1176.     case op of
  1177.  
  1178.         'Intersection': begin
  1179.             c = SetsIntersect(a, b, Count = count)
  1180.             iSize = count
  1181.         end
  1182.  
  1183.         'Subtraction': c = SetsSubtract(a, b, $
  1184.             Count=count, Intersect_Size=iSize)
  1185.  
  1186.         'Union': c = SetsUnion(a, b, $
  1187.            Count=count, Intersect_Size=iSize)
  1188.  
  1189.       endcase
  1190.  
  1191.       RETURN, c
  1192. end
  1193.  
  1194. ;----------------------------------------------------------------------------
  1195. ;
  1196. ;  PURPOSE:  Modify the calculator's text box based on the 'action'
  1197. ;            argument.
  1198. ;
  1199. ;  Side Effects:      XYOUTS text to the calculator's text box.
  1200. ;
  1201. function ModifyCalcText, $
  1202.     calcText, $   ; IN/OUT: calculator text
  1203.     gTextBox, $   ; IN: Calculator window ID
  1204.     flag, $       ; IN/OUT:
  1205.     action, $     ; IN: Operation (intersection, subtraction, or union)
  1206.     set, $        ; IN: Set object
  1207.     COLOR=color   ; IN: (opt) color of the calculator text box
  1208.  
  1209.     if (N_ELEMENTS(color) EQ 0) then $
  1210.           color = 0
  1211.  
  1212.     ;  Make the Calculator text box the active display, and determine the
  1213.     ;  sizing information
  1214.     ;
  1215.     WSET, gTextBox
  1216.     width = !D.X_SIZE
  1217.     height = !D.Y_SIZE
  1218.     xCharSize = !D.X_CH_SIZE
  1219.     yCharSize = !D.Y_CH_SIZE
  1220.  
  1221.     case action of
  1222.         'CLEAR': begin
  1223.             calcText = ''
  1224.             flag = 0
  1225.         end
  1226.  
  1227.         'DELETE': begin
  1228.             if (flag gt 0) then begin
  1229.                   flag = flag - 1
  1230.                   calcText = STRMID(calcText,0,(STRLEN(calcText)-3))
  1231.             endif else $
  1232.                   flag = 0
  1233.         end
  1234.  
  1235.         'ADD_SET': begin
  1236.             set -> GetProperty, Name = newText
  1237.             calcText = calcText + '!3' + newText
  1238.             flag = flag + 1
  1239.         end
  1240.  
  1241.         else: begin
  1242.             if (flag EQ 1) then begin
  1243.  
  1244.                 case action of
  1245.                     'Intersection': newText = '!93'
  1246.                     'Subtraction': newText = '!3-'
  1247.                     'Union': newText = '!91'
  1248.                 endcase
  1249.  
  1250.                 flag = flag + 1
  1251.                 calcText = calcText + newText
  1252.  
  1253.             endif else $
  1254.                 RETURN, 0b
  1255.         end
  1256.     endcase
  1257.  
  1258.     ;  Erase, and redraw the new text.
  1259.     ;
  1260.     ERASE
  1261.     XYOUTS, width - (xCharSize*flag)-10, $
  1262.         height*.3, calcText, COLOR = color, /DEVICE
  1263.  
  1264.     RETURN, 1B
  1265. end
  1266.  
  1267. ;----------------------------------------------------------------------------
  1268. ;
  1269. ;  PURPOSE:  Event handling procedure for Set Calculator's
  1270. ;            individual set buttons.
  1271. ;  Side Effects:      Updates the structure sState and the GUI.
  1272. ;
  1273. pro SetCalcButtonHandleEvents, $
  1274.     sEvent    ;  IN: event structure
  1275.  
  1276.     ;  Obtain the state structure which is store in the demo's top level base.
  1277.     ;
  1278.     WIDGET_CONTROL, sEvent.top, GET_UVALUE = sState, /NO_COPY
  1279.  
  1280.     ;  Obtain the user value of the widget which produced the event.
  1281.     ;
  1282.     WIDGET_CONTROL, sEvent.id, GET_UVALUE = userValue
  1283.  
  1284.     if (TAG_NAMES(sEvent, /STRUCTURE) EQ 'WIDGET_TRACKING') then begin
  1285.         WIDGET_CONTROL, sState.wTipsBox, SET_VALUE= $
  1286.           'Press one of these buttons to add a given set to the calculation.'
  1287.  
  1288.     endif else begin
  1289.  
  1290.         ;  Make a local copy of the calculator flag.
  1291.         ;  0 - nothing in the calculator text area
  1292.         ;  1 - the first set has been selected
  1293.         ;  2 - the first set and the set operator has been selected
  1294.         ;  3 - both sets and the operator has been selected
  1295.         ;
  1296.         calcFlag = sState.calcFlag
  1297.         setCalcText = sState.setCalcText
  1298.  
  1299.         ;  If the calculator is ready for a set to be selected then do this.
  1300.         ;
  1301.         if calcFlag EQ 0 or calcFlag EQ 2 then begin
  1302.             case calcFlag of
  1303.                 0: sState.set1 = sState.oSetList[userValue]  ; Set to 1st operand
  1304.                 2: sState.set2 = sState.oSetList[userValue]  ; Set to 2nd operand
  1305.             endcase
  1306.  
  1307.             ;   Modify the Calculator text boxes and update the calculator flag.
  1308.             ;
  1309.             if ModifyCalcText(setCalcText, sState.gCalcTextBox, calcFlag, $
  1310.                 'ADD_SET', sState.oSetList[userValue]) then begin
  1311.                 sState.calcFlag = calcFlag
  1312.                 sState.setCalcText = setCalcText
  1313.             endif
  1314.         endif
  1315.     endelse
  1316.  
  1317.     ;  Store the state structure back in the top level base's user value.
  1318.     ;
  1319.     WIDGET_CONTROL, sEvent.top, SET_UVALUE = sState, /NO_COPY
  1320. end
  1321.  
  1322.  
  1323. ;----------------------------------------------------------------------------
  1324. ;
  1325. ;  PURPOSE:  Event handling procedure for the  Set Calculator
  1326. ;            excluding the individual set buttons.
  1327. ;
  1328. ;  Side Effects:  Updates the structure sState and the GUI.
  1329. ;
  1330. pro SetCalcHandleEvents, $
  1331.     sEvent    ; IN: Event structure.
  1332.  
  1333.  
  1334.     WIDGET_CONTROL, sEvent.top, Get_UVALUE = sState, /NO_COPY
  1335.     WIDGET_CONTROL, sEvent.id, Get_UVALUE = uVal
  1336.  
  1337.     ;  Check for a Tracking event and update the Tips boxes as needed.
  1338.     ;
  1339.     if (TAG_NAMES(sEvent, /STRUCTURE) EQ 'WIDGET_TRACKING') then begin
  1340.         if (N_ELEMENTS(uVal) NE 0) then begin
  1341.  
  1342.             case uVal of
  1343.  
  1344.                 'Intersection': begin
  1345.                    tipText = 'Choose this button to perform a set Intersection.'
  1346.                 end
  1347.  
  1348.                 'Union': begin
  1349.                    tipText = 'Choose this button to perform a set Union.
  1350.                 end
  1351.  
  1352.                 'Subtraction': begin
  1353.                    tipText = 'Choose this button to perform a set Subtraction.'
  1354.                 end
  1355.  
  1356.                 'CLEAR': begin
  1357.                    tipText = 'Clear the calculator.'
  1358.                 end
  1359.  
  1360.                 'DELETE': begin
  1361.                    tipText = 'Erase the last calculator entry.'
  1362.                 end
  1363.  
  1364.                 'ENTER': begin
  1365.                    tipText = 'Press this button to accept the current set calculation.'
  1366.                 end
  1367.  
  1368.                 'CALC_TEXT': begin
  1369.                     tipText = 'This box shows the current set operation as it is typed.'
  1370.                 end
  1371.  
  1372.             endcase
  1373.  
  1374.         endif else tipText = ''
  1375.  
  1376.         WIDGET_CONTROL, sState.wTipsBox, SET_VALUE = tipText
  1377.  
  1378.     endif else begin
  1379.  
  1380.         ;  All other events are separated between an 'ENTER' event
  1381.         ;  and all the rest. The non-enter events only update the
  1382.         ;  Calculator Text box and certain flags.
  1383.         ;
  1384.         if (uVal ne 'ENTER') then begin
  1385.             calcFlag = sState.calcFlag
  1386.             setCalcText = sState.setCalcText
  1387.  
  1388.             if ModifyCalcText(setCalcText, sState.gCalcTextBox, $
  1389.                 calcFlag, uVal) then begin
  1390.  
  1391.                 ;  If the event was from an set operation button
  1392.                 ;  then store the op.
  1393.                 ;
  1394.                 if ((calcFlag EQ 2) AND (calcFlag gt sState.calcFlag)) then $
  1395.                     sState.op = uVal
  1396.                     sState.calcFlag = calcFlag
  1397.                     sState.setCalcText = setCalcText
  1398.                 endif
  1399.  
  1400.             endif else begin
  1401.  
  1402.                 ; This is an 'ENTER' event-- the equal button was pressed.
  1403.                 ;
  1404.                 if (sState.calcFlag EQ 3) then begin
  1405.                 if sState.numSets EQ sState.maxSets then $
  1406.                     void = $
  1407.                         DIALOG_MESSAGE('Too many sets.  Please Restart this demo.') $
  1408.  
  1409.                 else begin
  1410.  
  1411.                     ;  Get the data, names, and sizes of sets.
  1412.                     ;
  1413.                     sState.set1 -> GetProperty, DATA=set1Data, SIZE= $
  1414.                         set1Size, NAME=set1Name
  1415.                     sState.set2 -> GetProperty, DATA=set2Data, SIZE=$
  1416.                         set2Size, NAME=set2Name
  1417.  
  1418.                     ;  Perform the set operation and return the result.
  1419.                     ;
  1420.                     newData = DoSetOp( set1Data, set2Data, sState.op, $
  1421.                         COUNT=setSize, INTERSECT_SIZE=iSize)
  1422.  
  1423.                     ;  Determine Name of new Set.
  1424.                     ;
  1425.                     name = STRING(BYTE(sState.numSets) + 65b )
  1426.  
  1427.                     ;  Create a new set object.
  1428.                     ;
  1429.                     if setSize EQ 0 then $
  1430.                         newSet = OBJ_NEW('sets', name, $
  1431.                             SET1_SIZE=set1Size, SET2_SIZE=set2Size, $
  1432.                             OP=sState.op, SET1_NAME=set1Name, $
  1433.                             SET2_NAME=set2Name) $
  1434.                     else $
  1435.                         newSet = OBJ_NEW('sets', name, newData, $
  1436.                             SET1_SIZE=set1Size, SET2_SIZE=set2Size, $
  1437.                             OP=sState.op, SET1_NAME=set1Name, $
  1438.                             SET2_NAME=set2Name)
  1439.  
  1440.                     ;  Update the available set information.
  1441.                     ;
  1442.                     sState.numSets = sState.numSets + 1
  1443.                     sState.oSetList[sState.numSets-1] = newSet
  1444.                     sState.setNames[sState.numSets-1] = 'Set ' + name
  1445.  
  1446.                     ;  Update the GUI.
  1447.                     ;
  1448.                     WIDGET_CONTROL, sState.wCurrentSet, SET_VALUE = $
  1449.                         sState.setNames[0:sState.numSets-1]
  1450.  
  1451.                     WIDGET_CONTROL, sState.wCurrentSet, SET_DROPLIST_SELECT = $
  1452.                         sState.numSets-1
  1453.  
  1454.                     WIDGET_CONTROL, sState.wSetButtons[sState.numSets-1], $
  1455.                         SENSITIVE = 1
  1456.  
  1457.                     WIDGET_CONTROL, sState.wDataButtons[sState.numSets-1], $
  1458.                         SENSITIVE = 1
  1459.  
  1460.                     newSet->GetProperty, DESC = desc
  1461.  
  1462.                     WIDGET_CONTROL, sState.wDescText, SET_VALUE = desc
  1463.  
  1464.                     WIDGET_CONTROL, sState.wDescTitle, SET_VALUE = $
  1465.                         'Venn Diagram:  Set ' + name
  1466.  
  1467.  
  1468.                     DrawVennDiagram, set1Size, set2Size, setSize, set1Name, $
  1469.                         set2Name, name, sState.op, sState.gVennArea, $
  1470.                         COLORS = sState.colors
  1471.  
  1472.                     result = ModifyCalcText(sState.setCalcText, $
  1473.                         sState.gCalcTextBox, calcFlag,'CLEAR')
  1474.  
  1475.                     sState.calcFlag = 0
  1476.                     sState.setCalcText = ''
  1477.  
  1478.                 endelse
  1479.             endif else $
  1480.                 result = DIALOG_MESSAGE('Not a valid set operation.')
  1481.         endelse
  1482.     endelse
  1483.  
  1484.     WIDGET_CONTROL, sEvent.top, Set_UValue = sState, /NO_COPY
  1485.  
  1486. end
  1487.  
  1488. ;----------------------------------------------------------------------------
  1489. ;
  1490. ;  PURPOSE:  Cleanup proceduire for Venn
  1491. ;
  1492. ;  Side Effects:      Removes heap variables, and restores color settings
  1493. ;
  1494. pro CleanUpVenn, $
  1495.     wTop     ; IN: Top level base
  1496.  
  1497.     ;  Get the color table saved in the window's user value.
  1498.     ;
  1499.     WIDGET_CONTROL, wTop, GET_UVALUE = sState, /NO_COPY
  1500.  
  1501.     ;  Restore the previous color table and background system variable.
  1502.     ;
  1503.     TVLCT, sState.colorTable
  1504.     !P.BACKGROUND = sState.backgroundSave
  1505.  
  1506.     ;  Check for validity of existing Sets Objects and destroy them.
  1507.     ;
  1508.     if OBJ_VALID(sState.set1) then $
  1509.         OBJ_DESTROY, sState.set1
  1510.     if OBJ_VALID(sState.set2) then $
  1511.         OBJ_DESTROY, sState.set2
  1512.     OBJ_DESTROY, sState.oSetList
  1513.  
  1514.     if WIDGET_INFO(sState.groupBase, /VALID_ID) then $
  1515.         WIDGET_CONTROL, sState.groupBase, /MAP
  1516.  
  1517. end  ; of CleanupVenn
  1518.  
  1519.  
  1520. ;----------------------------------------------------------------------------
  1521. ;
  1522. ;  PURPOSE:  Main event handling routine for the Venn Demo.
  1523. ;
  1524. ;  Side Effects:   Updates sState, could display a Data Viewer, and modify
  1525. ;                  the GUI.
  1526. ;
  1527. pro VennHandleEvents, $
  1528.     sEvent      ; IN: event structure
  1529.  
  1530.     ;  Quit the application using the close box.
  1531.     ;
  1532.     if (TAG_NAMES(sEvent, /STRUCTURE_NAME) EQ $
  1533.         'WIDGET_KILL_REQUEST') then begin
  1534.         WIDGET_CONTROL, sEvent.top, /DESTROY
  1535.         RETURN
  1536.     endif
  1537.  
  1538.  
  1539.     WIDGET_CONTROL, sEvent.top, GET_UVALUE = sState, /No_Copy
  1540.     WIDGET_CONTROL, sEvent.id, GET_UVALUE = uVal
  1541.  
  1542.     if (TAG_NAMES(sEvent, /STRUCTURE) EQ 'WIDGET_TRACKING') then begin
  1543.  
  1544.         if (N_ELEMENTS(uVal) NE 0) then begin
  1545.  
  1546.             case uVal of
  1547.  
  1548.                 'CURRENT': begin
  1549.                     tipText = 'Select a set from this droplist' + $
  1550.                               ' to view its Venn Diagram and description.'
  1551.                 end
  1552.  
  1553.                 'DESC': begin
  1554.                     tipText = 'This is a description of the set' + $
  1555.                               ' you are currently viewing.'
  1556.                 end
  1557.  
  1558.                 'VENN': begin
  1559.                     tipText = 'This is the Venn diagram for the' + $
  1560.                               ' set you are currently viewing.'
  1561.                 end
  1562.  
  1563.                 else: tipText = ''
  1564.  
  1565.             endcase
  1566.  
  1567.         endif else tipText = ''
  1568.  
  1569.         WIDGET_CONTROL, sState.wTipsBox, SET_VALUE = tipText
  1570.  
  1571.     endif else begin
  1572.  
  1573.         case uVal of
  1574.  
  1575.             'CURRENT': begin
  1576.                 sState.oSetList[sEvent.index]->GetProperty, $
  1577.                     DESC=desc, NAME=name, $
  1578.                     OP=op, SET1_NAME=set1Name, SET2_NAME=set2Name, $
  1579.                     SET1_SIZE=set1Size, SET2_SIZE=set2Size, SIZE=size
  1580.  
  1581.                 WIDGET_CONTROL, sState.wDescTitle, $
  1582.                     SET_VALUE='Venn Diagram:  Set ' + name
  1583.  
  1584.                 DrawVennDiagram, set1Size, set2Size, size, set1Name, $
  1585.                     set2Name, name, op, sState.gVennArea, $
  1586.                     COLORS = sState.colors
  1587.  
  1588.                 WIDGET_CONTROL, sState.wDescText, SET_VALUE = desc
  1589.             end
  1590.  
  1591.             'HELP' : begin
  1592.  
  1593.                 ;  Display the 'online help' for this demo.
  1594.                 ;
  1595.                 if( Xregistered('XDisplayFile') NE 0) then RETURN
  1596.                    XDisplayFile, filepath('venn.txt', $
  1597.                       SUBDIR = ['examples','demo','demotext']), $
  1598.                     DONE_BUTTON='Done', $
  1599.                     TITLE="About Venn Demo" , $
  1600.                     GROUP=sEvent.top, WIDTH=55, HEIGHT=14
  1601.  
  1602.             end           ;  of Help
  1603.  
  1604.             'QUIT' : begin
  1605.                 WIDGET_CONTROL, sEvent.top, SET_UVALUE = sState, /NO_COPY
  1606.                 WIDGET_CONTROL, sEvent.top, /DESTROY
  1607.                 RETURN
  1608.             end
  1609.  
  1610.             else: begin
  1611.  
  1612.                 ;  Display the given set's data if it is not already displayed.
  1613.                 ;  If it is displayed then bring it to the front.
  1614.                 ;
  1615.                 index = WHERE(uVal EQ sState.setNames, count)
  1616.  
  1617.                 if (count NE 0) then begin
  1618.                     if WIDGET_INFO(sState.wDataViewers[index], $
  1619.                         /VALID_ID) then $
  1620.                         WIDGET_CONTROL, sState.wDataViewers[index], /SHOW $
  1621.                     else begin
  1622.                         oSet = sState.oSetList[index]
  1623.                         oSet->GetProperty, DATA = data, NAME = name
  1624.  
  1625.                         if (N_ELEMENTS(data) EQ 0) then $
  1626.                             junk = DIALOG_MESSAGE('This is the Empty set', $
  1627.                                 TITLE = 'Set ' + name, /INFORMATION) $
  1628.                         else $
  1629.                             sState.wDataViewers[index] = DataViewer(data, $
  1630.                                 TITLE = 'Set '+ name, GROUP_LEADER = sEvent.top)
  1631.                     endelse
  1632.                 endif
  1633.  
  1634.             end      ;   of else
  1635.  
  1636.         endcase
  1637.  
  1638.     endelse
  1639.  
  1640.     WIDGET_CONTROL, sEvent.top, SET_UVALUE = sState, /NO_COPY
  1641. end
  1642.  
  1643. ;----------------------------------------------------------------------------
  1644. ;
  1645. ;  PURPOSE: Main procedure of the Venn demo
  1646. ;
  1647. pro D_Venn, $
  1648.     set1, set2, set3, set4, set5, set6, $ ; IN: sets objects
  1649.     GROUP=group, $                        ; IN: (opt) group identifier
  1650.     APPTLB = appTLB                       ; OUT: (opt) TLB of this application
  1651.  
  1652.     ;  Check for the proper # of arguments.
  1653.     ;
  1654.     if (N_PARAMS() GT 6) then $
  1655.         MESSAGE, 'Called with too many arguments.'
  1656.  
  1657.     ;  Check the validity of the group identifier.
  1658.     ;
  1659.     ngroup = N_ELEMENTS(group)
  1660.     if (ngroup NE 0) then begin
  1661.         check = WIDGET_INFO(group, /VALID_ID)
  1662.         if (check NE 1) then begin
  1663.             print,'Error, the group identifier is not valid'
  1664.             print, 'Return to the main application'
  1665.             RETURN
  1666.         endif
  1667.         groupBase = group
  1668.     endif else groupBase = 0L
  1669.  
  1670.     ;  Get the current color vectors to restore
  1671.     ;  when this application is exited.
  1672.     ;
  1673.     TVLCT, savedR, savedG, savedB, /GET
  1674.  
  1675.     ;  Build color table from color vectors.
  1676.     ;
  1677.     colorTable = [[savedR],[savedG],[savedB]]
  1678.  
  1679.     ;  Create the starting up message.
  1680.     ;
  1681.     if (ngroup EQ 0) then begin
  1682.         drawbase = startmes()
  1683.     endif else begin
  1684.         drawbase = startmes(GROUP=group)
  1685.     endelse
  1686.  
  1687.     ;  If possible, force the system to use 256 colors.
  1688.     ;
  1689.     if((( !D.NAME EQ 'X') OR (!D.NAME EQ 'MAC')) $
  1690.         AND (!D.N_COLORS GE 256L)) then $
  1691.         DEVICE, PSEUDO_COLOR = 8
  1692.  
  1693.     DEVICE, DECOMPOSED = 0, BYPASS_TRANSLATION = 0
  1694.  
  1695.  
  1696.     ;  Set up a Tek Color Table.
  1697.     ;
  1698.     TEK_COLOR
  1699.     colors = INTARR(32)
  1700.     colors[0] = 4 ;Set result color to blue
  1701.     colors[1] = 2 ;Set set A color to red
  1702.     colors[2] = 3 ;Set set B color to green
  1703.     colors[3] = 0 ;Set text color to black
  1704.     colors[4] = 1 ;Set background to white
  1705.  
  1706.     ;  Save incoming and set the background to white.
  1707.     ;
  1708.     backgroundSave = !P.BACKGROUND
  1709.     !P.BACKGROUND = colors[4]
  1710.  
  1711.     ;  Load the calculator bitmap buttons.
  1712.     ;
  1713.     LoadCalcBitmaps, bmDelete, bmClear, bmIntersect, $
  1714.         bmUnion, bmSubtract, bmEnter
  1715.  
  1716.     ;  Allow for only 15 available sets.
  1717.     ;
  1718.     maxSets = 15
  1719.  
  1720.     ; Define a main widget base.
  1721.     ;
  1722.     if (N_ELEMENTS(group) EQ 0) then begin
  1723.         wTop = WIDGET_BASE(TITLE="Venn Demo", /COLUMN, $
  1724.             MAP=0, $
  1725.             /TLB_KILL_REQUEST_EVENTS, $
  1726.             TLB_FRAME_ATTR = 1, Mbar = wMenuBar)
  1727.     endif else begin
  1728.         wTop = WIDGET_BASE(TITLE="Venn Demo", /COLUMN, $
  1729.             MAP=0, $
  1730.             /TLB_KILL_REQUEST_EVENTS, $
  1731.             TLB_FRAME_ATTR = 1, Mbar = wMenuBar, $
  1732.             GROUP_LEADER=group)
  1733.     endelse
  1734.  
  1735.     appTlb = wTop
  1736.  
  1737.         ;  Create the menu bar item file that contains the exit button.
  1738.         ;
  1739.         wFileMenu = WIDGET_BUTTON(wMenuBar, VALUE='File', /MENU)
  1740.  
  1741.             wQuitItem = WIDGET_BUTTON(wFileMenu, VALUE='Quit', UVALUE='QUIT')
  1742.  
  1743.         ;  Create Options Menu
  1744.         ;
  1745.         wOptionsMenu = WIDGET_BUTTON(wMenuBar, VALUE='Options', /MENU)
  1746.  
  1747.             wDataMenu = WIDGET_BUTTON(wOptionsMenu, $
  1748.                 VALUE='View Set Data' ,/MENU)
  1749.         wDataButtons = LONARR(maxSets)
  1750.         for i = 0, maxSets-1 do begin
  1751.                 name = STRING(65B + BYTE(i))
  1752.                        wDataButtons[i] = WIDGET_BUTTON(wDataMenu, VALUE = $
  1753.                             'Set '+ name, UVALUE = 'Set '+ name)
  1754.             WIDGET_CONTROL, wDataButtons[i], SENSITIVE = 0
  1755.         endfor
  1756.  
  1757.         ; Create Help Menu
  1758.         ;
  1759.         wHelpMenu = WIDGET_BUTTON(wMenuBar, VALUE='About', /HELP, /MENU)
  1760.  
  1761.              wHelpItem = WIDGET_BUTTON(wHelpMenu, $
  1762.                  VALUE='About Venn Demo...', UVALUE='HELP')
  1763.  
  1764.         ;  Create the first child of the top level base(wTop).
  1765.         ;
  1766.         wTopRowBase = WIDGET_BASE(wTop, Column = 2,/Frame, /TRACK)
  1767.  
  1768.             ;  Create a base for the left column.
  1769.             ;
  1770.             wLeftBase = WIDGET_BASE(wTopRowBase,/BASE_ALIGN_CENTER, $
  1771.                 Column=1, /TRACK)
  1772.  
  1773.                 ;  Calculator.
  1774.                 ;
  1775.                 wSetCalcTitle = WIDGET_LABEL(wLeftBase, $
  1776.                     VALUE='Set Calculator', /TRACK)
  1777.  
  1778.                 wSetCalcBase = WIDGET_BASE(wLeftBase, /COLUMN , /FRAME, $
  1779.                      /BASE_ALIGN_RIGHT, /TRACK)
  1780.                       wSetCalcText = LONARR(3)
  1781.  
  1782.                       wSetCalcTextBase = WIDGET_BASE(wSetCalcBase, /ROW, /TRACK, $
  1783.                           EVENT_PRO = 'SetCalcHandleEvents')
  1784.  
  1785.                           wSetCalcTextBox = WIDGET_DRAW(wSetCalcTextBase, $
  1786.                               UVALUE = 'CALC_TEXT', $
  1787.                               XSIZE = 100, YSIZE = 25, RETAIN = 2, /TRACKING_EVENTS)
  1788.  
  1789.                           wCalcDeleteButton = WIDGET_BUTTON(wSetCalcTextBase, $
  1790.                               VALUE = bmDelete, /TRACKING_EVENTS, UVALUE = 'DELETE')
  1791.  
  1792.                       wButtonsBase = WIDGET_BASE(wSetCalcBase, $
  1793.                           UVALUE='BUTTONS', /ROW, /TRACK)
  1794.  
  1795.                           wSetButtonsBase = WIDGET_BASE(wButtonsBase, $
  1796.                               /GRID_LAYOUT, ROW=5, /TRACKING_EVENTS, $
  1797.                               EVENT_PRO='SetCalcButtonHandleEvents')
  1798.  
  1799.                               wSetButtons = LONARR(maxSets)
  1800.  
  1801.                               for i = 0B, 14B do begin
  1802.                                   wSetButtons[i] = WIDGET_BUTTON(wSetButtonsBase, $
  1803.                                       FONT = calcTextFont, $
  1804.                                       VALUE=STRING(65B+i), /TRACKING_EVENTS, $
  1805.                                       UVALUE = i)
  1806.                                   WIDGET_CONTROL, wSetButtons[i], SENSITIVE = 0
  1807.                               endfor
  1808.  
  1809.                           wOpsButtonsBase = WIDGET_BASE(wButtonsBase, /TRACK, $
  1810.                               /GRID_LAYOUT, ROW=5, EVENT_PRO='SetCalcHandleEvents')
  1811.  
  1812.                               wClearButton = WIDGET_BUTTON(wOpsButtonsBase, $
  1813.                                   VALUE=bmClear, UVALUE='CLEAR', $
  1814.                                   /TRACKING_EVENTS)
  1815.  
  1816.                               wIntersectButton = WIDGET_BUTTON(wOpsButtonsBase, $
  1817.                                   VALUE=bmIntersect, UVALUE='Intersection', $
  1818.                                   /TRACKING_EVENTS)
  1819.  
  1820.                              wSubtractButton = WIDGET_BUTTON(wOpsButtonsBase, $
  1821.                                  VALUE = bmSubtract, $
  1822.                                  UVALUE = 'Subtraction', /TRACKING_EVENTS)
  1823.  
  1824.                              wUnionButton = WIDGET_BUTTON(wOpsButtonsBase, $
  1825.                                  VALUE=bmUnion, UVALUE='Union', $
  1826.                                  /TRACKING_EVENTS)
  1827.  
  1828.                              wEnterButton = WIDGET_BUTTON(wOpsButtonsBase, $
  1829.                                  VALUE=bmEnter, UVALUE='ENTER',  $
  1830.                                  /TRACKING_EVENTS)
  1831.  
  1832.                 wCurrentSetBase = WIDGET_BASE(wLeftBase,  /COLUMN, /TRACK)
  1833.  
  1834.                     wCurrentSet = WIDGET_DROPLIST(wCurrentSetBase, $
  1835.                         VALUE='', /DYNAMIC_RESIZE, $
  1836.                         TITLE='Currently Viewing: ', $
  1837.                         UVALUE = 'CURRENT', /TRACKING_EVENTS)
  1838.  
  1839.             wRightBase = WIDGET_BASE(wTopRowBase, /COLUMN, /TRACK)
  1840.  
  1841.                 wDescTitle = WIDGET_LABEL(wRightBase, /TRACK, $
  1842.                     VALUE='Venn Diagram:  Set A', /ALIGN_CENTER, XSIZE=250)
  1843.  
  1844.                 ;  Create the drawing area for the Venn diagram.
  1845.                 ;
  1846.                 text = ['Set A contains 34 integers.' + $
  1847.                         ' The minimum is -34 and the maximum is 56.']
  1848.  
  1849.                 wVennDraw  = WIDGET_DRAW(wRightBase, XSIZE=300,$
  1850.                     YSIZE=250, RETAIN=2, UVALUE='VENN', /TRACKING_EVENTS)
  1851.  
  1852.                 wDescText = WIDGET_TEXT(wRightBase, VALUE=text, YSIZE=4, $
  1853.                     SCR_XSIZE=250, /WRAP, /TRACKING_EVENTS, UVALUE='DESC')
  1854.  
  1855.         ;  Create the second child of the top level base(wTop)
  1856.         ;  This is the status window
  1857.         ;
  1858.         wBottomRowBase = WIDGET_BASE(wTop, /ROW)
  1859.  
  1860.             ;  Create the widget label of the status window.
  1861.             ;
  1862.        widthTips = 72
  1863.        wTipsBox = WIDGET_TEXT(wBottomRowBase, $
  1864.                                xsize = widthTips, ysize=1, $
  1865.                                value = string(replicate(32b, widthTips)))
  1866.  
  1867.  
  1868.     ;  Initialize the set arrays and counter variable.
  1869.     ;
  1870.     numSets = 0
  1871.     oSetList = OBJARR(maxSets)
  1872.     setNames = STRARR(maxSets)
  1873.  
  1874.     ;  Determine if the user passed in set data to the Venn demo.
  1875.     ;  If the data is valid, then add a set and modify the GUI.
  1876.     ;
  1877.     count = 1
  1878.     index = 0
  1879.     while (count LE N_PARAMS()) do begin
  1880.  
  1881.         case count of
  1882.             1:     tmpData = set1
  1883.             2:  tmpData = set2
  1884.             3:  tmpData = set3
  1885.             4:  tmpData = set4
  1886.             5:  tmpData = set5
  1887.             6:  tmpData = set6
  1888.         endcase
  1889.  
  1890.         if (ValidSetData(tmpData)) then begin
  1891.             CreateSet, wSetButtons[index], wDataButtons[index], numSets, oSetList, $
  1892.                 setNames, DATA = tmpData
  1893.             index = index + 1
  1894.         endif
  1895.  
  1896.         count = count + 1
  1897.  
  1898.     endwhile
  1899.  
  1900.     ;  Guarantee at least two sets are loaded.
  1901.     ;
  1902.     if (index LT 2) then $
  1903.         for i = index,1 do $
  1904.             CreateSet, wSetButtons[i], wDataButtons[i], numSets, oSetList, $
  1905.                 setNames, SEED=seed
  1906.  
  1907.        ;  Realize the widget hierarchy.
  1908.        ;
  1909.        WIDGET_CONTROL, wTop, /REALIZE
  1910.  
  1911.     ;  Store all the currently available Set names in the Viewing Droplist.
  1912.     ;
  1913.     WIDGET_CONTROL, wCurrentSet, SET_VALUE = setNames[0:numSets-1]
  1914.  
  1915.     ;  Obtain the id of the Venn drawing area and the Set Calculator Text area.
  1916.     ;  Also draw the background as White.
  1917.     ;
  1918.     WIDGET_CONTROL, wVennDraw, GET_VALUE=gVennArea
  1919.     WIDGET_CONTROL, wSetCalcTextBox, GET_VALUE=gCalcTextBox
  1920.     WSET, gCalcTextBox
  1921.     ERASE
  1922.     WSET, gVennArea
  1923.     ERASE
  1924.  
  1925.     ;  Update GUI to display information for first Set.
  1926.     ;
  1927.     setIndex = 0
  1928.     oSetList[setIndex]->GetProperty, DESC=desc, NAME=name, SIZE=size
  1929.     WIDGET_CONTROL, wDescTitle, SET_VALUE='Venn Diagram:  Set ' + name
  1930.     DrawVennDiagram, 0, 0, size, '', '', name, '', gVennArea, COLORS=colors
  1931.     WIDGET_CONTROL, wDescText, SET_VALUE=desc
  1932.  
  1933.     ;  Now that the GUI is completely initialize, we will map it to the screen
  1934.     ;WIDGET_CONTROL, wTop, UPDATE = 1
  1935.  
  1936.     ;  Initialize the state structure.
  1937.     ;  This holds all the information used for this Demo.
  1938.     ;
  1939.     state={ $
  1940.         colorTable: colorTable, $           ; Original Color Table
  1941.         backgroundSave: backgroundSave, $   ; Original !P.BACKGROUND
  1942.         wDataButtons:wDataButtons, $        ; IDs of View set data buttons
  1943.         wLeftBase: wLeftBase, $             ; ID of Calculator Base
  1944.         setCalcText: '', $                  ; Current calculator text
  1945.         wSetButtonsBase:wSetButtonsBase, $  ; ID of base for Calculator set buttons
  1946.         wSetButtons:wSetButtons, $          ; IDs of all the set buttons
  1947.         wDescTitle:wDescTitle, $            ; ID of Venn Diagram Title
  1948.         wDescText:wDescText , $             ; ID of text widget holding
  1949.                                             ; Set descriptions
  1950.         wCurrentSet:wCurrentSet, $          ; ID of Viewing Current droplist
  1951.         setNames:setNames, $                ; Current list of Set names
  1952.         gVennArea: gVennArea, $             ; Graphics window ID of the Venn Diagram
  1953.         gCalcTextBox:gCalcTextBox, $        ; Graphics window ID of Calculator text
  1954.         wTipsBox : wTipsBox, $            ; IDs of the Tips text boxes
  1955.         calcFlag:0B , $                     ; Flag to indicate calculator status
  1956.         set1 : OBJ_NEW('sets'), $           ; First Set used in the set operation
  1957.         set2 : OBJ_NEW('sets'), $           ; Second Set used in the set operation
  1958.         colors: colors, $                   ; The current colors for displaying
  1959.                                             ; The Venn Diagram
  1960.         op : '', $                          ; Flag denoting Set Operation
  1961.                                             ; 0 - Minus , 1 - Intersection,
  1962.                                             ; 2 - Union
  1963.         setIndex:setIndex, $                ; Index of currently viewed set
  1964.         numSets:numSets, $                  ; Total # of available sets
  1965.         maxSets: maxSets, $                 ; Maximum # of sets possible
  1966.         oSetList: oSetList,  $              ; Array of 20 Set Objects
  1967.         wDataViewers:LONARR(maxSets), $     ; IDs of individual Data Viewers
  1968.         groupBase: groupBase $              ; Base of Group Leader
  1969.     }
  1970.  
  1971.  
  1972.  
  1973.    ;   Register the info structure in the user value of the top-level base
  1974.    ;
  1975.    WIDGET_CONTROL, wTop, SET_UVALUE=state, /NO_COPY
  1976.  
  1977.     ;  Destroy the starting up window.
  1978.     ;
  1979.     WIDGET_CONTROL, drawbase, /DESTROY
  1980.  
  1981.     ;  Map the top level base.
  1982.     ;
  1983.     WIDGET_CONTROL, wTop, MAP=1
  1984.  
  1985.    ;  Register with the XMANAGER.
  1986.    ;
  1987.    XMANAGER, 'D_Venn', wTop, $
  1988.        EVENT_HANDLER = 'VennHandleEvents', $
  1989.        /NO_BLOCK, CLEANUP = 'CleanUpVenn'
  1990.  
  1991. end   ; D_Venn
  1992.